/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.web.common.utility;

import org.apache.commons.lang3.StringUtils;

import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * description:
 *
 * @author Noah Guo
 * @date 2021/03/17
 */
public class StringUtility {

    private static final Pattern pattern = Pattern.compile("[0-9]*");

    private StringUtility() {
    }

    /**
     * 判断字符串是不是以数字开头
     *
     * @param str
     * @return
     */
    public static boolean isStartWithNumber(String str) {
        if (isNullOrEmpty(str)) {
            return false;
        }
        Matcher isNum = pattern.matcher(str.charAt(0) + "");
        return isNum.matches();
    }

    /**
     *
     */
    public static String contactByRemovingRepeat(String firstStr, String secondStr) {
        return contactByRemovingRepeat(firstStr, secondStr, true);
    }

    /**
     * 移除字符串所有换行符
     *
     * @param source
     * @return
     */
    public static String removeNewLineParameter(String source) {
        if (isNullOrEmpty(source)) {
            return source;
        }
        return source.replaceAll("(\\r\\n|\\n)", "");
    }

    /**
     * 判断字符串是否是html
     *
     * @param text
     * @return
     */
    public static boolean isHtml(String text) {
        final String htmlPattern = "<.*?>";
        Pattern pattern = Pattern.compile(htmlPattern, Pattern.DOTALL);
        return pattern.matcher(text).find();
    }

    /**
     * 合并两个字符串，并移除头尾连接时的重复字符串。
     * 实例：
     * ContactByRemoveRepeat("1234", "456")的返回结果是 "123456"
     *
     * @param firstStr        第一个字符串
     * @param secondStr       第二个字符串
     * @param isCaseSensitive 是否大小写敏感
     * @return 合并后字符串
     */
    public static String contactByRemovingRepeat(String firstStr, String secondStr, boolean isCaseSensitive) {
        if (isNullOrEmpty(firstStr)) {
            return secondStr;
        }

        if (isNullOrEmpty(secondStr)) {
            return firstStr;
        }

        char[] firstArray = firstStr.toCharArray();
        char[] secondArray = secondStr.toCharArray();
        int index = -1;

        for (int i = 0; i < firstArray.length; i++) {
            if (secondArray[0] != firstArray[i]) {
            } else {
                boolean containSameSubString = false;
                int j = i, k = 0;
                for (; j < firstArray.length; j++) {
                    if (isEqual(firstArray[j], secondArray[k], isCaseSensitive)) {
                        k++;
                    } else {
                        break;
                    }
                }
                if (j == firstArray.length) {
                    containSameSubString = true;
                }
                if (containSameSubString) {
                    index = i;
                    break;
                }
            }
        }

        if (index > -1) {
            return firstStr.substring(0, index) + secondStr;
        } else {
            return firstStr + secondStr;
        }
    }

    /**
     * <pre>
     * StringUtils.isBlank(null)      = true
     * StringUtils.isBlank("")        = true
     * StringUtils.isBlank(" ")       = true
     * StringUtils.isBlank("bob")     = false
     * StringUtils.isBlank("  bob  ") = false
     * </pre>
     *
     * @param source
     * @return
     */
    public static boolean isBlank(String source) {
        return StringUtils.isBlank(source);
    }


    /**
     * 判断字符串是否是null或empty
     *
     * @param source 源字符串
     * @return
     */
    public static boolean isNullOrEmpty(String source) {
        return source == null || source.isEmpty();
    }

    /**
     * 判断字符串非null且非空
     *
     * @param source
     * @return
     */
    public static boolean isNotNullOrEmpty(String source) {
        return !isNullOrEmpty(source);
    }

    /**
     * 如果源字符串不为null或空 那么执行后续的consumer动作
     *
     * @param source
     * @param consumerAction
     */
    public static void executeIfPresent(String source, Consumer<String> consumerAction) {
        executeIfPresent(source, StringUtility::isNotNullOrEmpty, consumerAction);
    }

    /**
     * 如果present 则执行consumerAction
     *
     * @param source
     * @param predicateAction
     * @param consumerAction
     */
    public static void executeIfPresent(String source, Predicate<String> predicateAction, Consumer<String> consumerAction) {
        executeIfPresentOrOther(source, predicateAction, consumerAction, null);
    }

    /**
     * 按照条件执行对应的action动作
     *
     * @param source
     * @param predicateAction
     * @param consumerAction
     * @param otherAction
     */
    public static void executeIfPresentOrOther(String source, Predicate<String> predicateAction, Consumer<String> consumerAction, Consumer<String> otherAction) {
        if (predicateAction != null) {
            if (predicateAction.test(source)) {
                if (consumerAction != null) {
                    consumerAction.accept(source);
                }
            } else {
                if (otherAction != null) {
                    otherAction.accept(source);
                }
            }
        }
    }

    /**
     * 判断字符串是否是null或empty
     *
     * @param source 源字符串
     * @return
     */
    public static boolean isNull(String source) {
        return source == null;
    }

    /**
     * 比较两个字符是否相等，如果字符是字母且禁用大小写敏感开关，那字母的相等不区分大小写。
     * 如在禁用大小写敏感开关时，a等于A
     */
    private static boolean isEqual(char c1, char c2, boolean isCaseSensitive) {
        if (Character.isLetter(c1) && Character.isLetter(c2) && !isCaseSensitive) {
            // 大小写字母Unicode码值差为 32 或 0
            return Math.abs(c1 - c2) == 32 || c1 == c2;
        } else {
            // 非字母（直接比较）
            return c1 == c2;
        }
    }

    /**
     * 使用默认值
     *
     * @param source
     * @param defaultValue
     * @return
     */
    public static String getOrDefault(String source, String defaultValue) {
        if (isNullOrEmpty(source)) {
            return isNullOrEmpty(defaultValue) ? "" : defaultValue;
        }
        return source;
    }

    /**
     * 获取对应值或默认值
     *
     * @param source
     * @param defaultValue
     * @return
     */
    public static String getOrDefault(Object source, String defaultValue) {
        if (source == null) {
            return isNullOrEmpty(defaultValue) ? "" : defaultValue;
        }
        return source.toString();
    }

    /**
     * 将null 转换成空字符串
     *
     * @param source
     * @return
     */
    public static String convertNullToEmptyString(String source) {
        if (isNullOrEmpty(source)) {
            return "";
        }
        return source;
    }

    public static boolean startWith(String a, String b) {
        if (a == null || b == null) {
            return false;
        }
        if (a.indexOf(':') > -1 && b.indexOf(':') > -1) {
            if (a.substring(0, 1).equalsIgnoreCase(b.substring(0, 1))) {
                a = a.substring(a.indexOf(':') + 1);
                b = b.substring(b.indexOf(':') + 1);
            } else {
                return false;
            }
        } else if (a.indexOf(':') > -1) {
            a = a.substring(a.indexOf(':') + 1);
        } else if (b.indexOf(':') > -1) {
            b = b.substring(b.indexOf(':') + 1);
        }

        return a.startsWith(b);
    }


    /**
     * 判断两个字符串是否相同
     *
     * @param source 源字符串
     * @param target 目标字符串
     * @return 是否相同的标识
     */
    public static boolean equals(String source, String target) {
        return StringUtils.equals(source, target);
    }

    /**
     * 不区分大小写的字符串比较
     *
     * @param source 源字符串
     * @param target 目标字符串
     * @return
     */
    public static boolean equalsIgnoreCase(String source, String target) {
        return StringUtils.equalsIgnoreCase(source, target);
    }

    /**
     * 首字母小写32为是char类型大小写的差数，-32是小写变大写，+32是大写变小写
     *
     * @param str
     * @return
     */
    public static String lowerFirstCase(String str) {
        if (isNullOrEmpty(str)) {
            return str;
        }
        char[] chars = str.toCharArray();
        //首字母小写方法，大写会变成小写，如果小写首字母会消失
        chars[0] += 32;
        return String.valueOf(chars);
    }

    /**
     * 将横线替换为下划线
     *
     * @param source
     * @return
     */
    public static String replaceLineToUnderLine(String source) {
        if (isNullOrEmpty(source)) {
            return source;
        }
        return source.replaceAll("-", "_");
    }


    /**
     * 将横线替换为下划线
     *
     * @param source
     * @return
     */
    public static String replaceDotToUnderLine(String source) {
        if (isNullOrEmpty(source)) {
            return source;
        }
        return source.replaceAll("\\.", "_");
    }

    /**
     * 首字母大写 32为是char类型大小写的差数，-32是小写变大写，+32是大写变小写
     *
     * @param str
     * @return
     */
    public static String upperFirstCase(String str) {
        if (isNullOrEmpty(str)) {
            return str;
        }
        char[] chars = str.toCharArray();
        //首字母小写方法，大写会变成小写，如果小写首字母会消失
        chars[0] -= 32;
        return String.valueOf(chars);
    }

    /**
     * 将字符串转换成为小写形式
     * 如果传递的字符串为null  那么返回空字符串而不会引起空引用问题
     *
     * @param source
     * @return
     */
    public static String toLowerCase(String source) {
        if (isNullOrEmpty(source)) {
            return "";
        }
        return source.toLowerCase();
    }

    /**
     * 将字符串转换成为大写形式
     * 如果字符串为null，那么返回空字符串，避免引起空引用异常
     *
     * @param source
     * @return
     */
    public static String toUpperCase(String source) {
        if (isNullOrEmpty(source)) {
            return "";
        }
        return source.toUpperCase();
    }

    /**
     * 转换成为camel形式
     *
     * @param s
     * @return
     */
    public static String toCamelCase(String s) {
        if (StringUtils.isEmpty(s) || !Character.isUpperCase(s.charAt(0))) {
            return s;
        }

        char[] chars = s.toCharArray();

        for (int i = 0; i < chars.length; i++) {
            if (i == 1 && !Character.isUpperCase(chars[i])) {
                break;
            }

            boolean hasNext = (i + 1 < chars.length);
            if (i > 0 && hasNext && !Character.isUpperCase(chars[i + 1])) {
                // if the next character is a space, which is not considered uppercase
                // (otherwise we wouldn't be here...)
                // we want to ensure that the following:
                // 'FOO bar' is rewritten as 'foo bar', and not as 'foO bar'
                // The code was written in such a way that the first word in uppercase
                // ends when if finds an uppercase letter followed by a lowercase letter.
                // now a ' ' (space, (char)32) is considered not upper
                // but in that case we still want our current character to become lowercase
                if (Character.isSpaceChar(chars[i + 1])) {
                    chars[i] = toLower(chars[i]);
                }

                break;
            }

            chars[i] = toLower(chars[i]);
        }

        return new String(chars);
    }

    private static char toLower(char c) {
        c = Character.toLowerCase(c);
        return c;
    }

    /**
     * 移除字符串两端指定的字符
     *
     * @param source
     * @param beTrim
     * @return
     */
    public static String trimStringWith(String source, List<Character> beTrim) {
        int st = 0;
        int len = source.length();
        char[] val = source.toCharArray();

        while ((st < len) && (beTrim.contains(val[st]))) {
            st++;
        }
        while ((st < len) && (beTrim.contains(val[len - 1]))) {
            len--;
        }
        return ((st > 0) || (len < source.length())) ? source.substring(st, len) : source;
    }
}
